package com.monster.datasourcejob.tablebuildingsql.parser.impl;

import com.monster.datasourcejob.model.Field;
import com.monster.datasourcejob.tablebuildingsql.parser.TableBuildingSqlParser;
import org.apache.commons.lang3.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * description:
 *
 * @author Yuanml on 2021/6/29 11:39
 */
public class MysqlTableBuildingSqlParser implements TableBuildingSqlParser {
    public static final String[] MYSQL_FIELD_TYPE_ARR = new String[]{"DECIMAL","DECIMAL UNSIGNED","TINYINT","TINYINT UNSIGNED","BOOLEAN","SMALLINT","SMALLINT UNSIGNED","INT","INT UNSIGNED","FLOAT","FLOAT UNSIGNED","DOUBLE","DOUBLE UNSIGNED","NULL","TIMESTAMP","BIGINT","BIGINT UNSIGNED","MEDIUMINT","MEDIUMINT UNSIGNED","DATE","TIME","DATETIME","YEAR","VARCHAR","VARBINARY","BIT","JSON","ENUM","SET","TINYBLOB","TINYTEXT","MEDIUMBLOB","MEDIUMTEXT","LONGBLOB","LONGTEXT","BLOB","TEXT","CHAR","BINARY","GEOMETRY","UNKNOWN"};
    public static final Map<String, Boolean> MYSQL_FIELD_TYPE_MAP = new HashMap<>(MYSQL_FIELD_TYPE_ARR.length);
    static {
        for (String type : MYSQL_FIELD_TYPE_ARR) {
            MYSQL_FIELD_TYPE_MAP.put(type, true);
        }
    }

    /**
     * 将建表sql通过换行符分割而来的每一行sql语句字符串
     */
    private final String[] rows;
    public MysqlTableBuildingSqlParser(String tableBuildingSql) {
        if (StringUtils.isBlank(tableBuildingSql)) {
            throw new IllegalArgumentException("the sql to build table can't be empty");
        }
        this.rows = tableBuildingSql.split("\n");
    }

    @Override
    public List<Field> getFields() {
        List<String> strContainsFieldList =  getContainFieldStr();
        return getFields(strContainsFieldList);
    }

    @Override
    public String getTableName() {
        String[] split = rows[0].trim().split(" ");
        String tableName = split[2].replace("`", "").replace("(", "").trim();
        String[] dataBaseAndTableName = tableName.split("\\.");
        if (dataBaseAndTableName.length > 1) {
            tableName = dataBaseAndTableName[1];
        }
        return tableName;
    }

    @Override
    public String getTableComment() {
        String lastRow = rows[rows.length - 1];
        String[] els = lastRow.split(" ");
        for (String el : els) {
            if (el.contains("COMMENT=")) {
                return el.replace("\t", "")
                        .replace("\n", "")
                        .replace("COMMENT=", "")
                        .replace("'", "")
                        .trim();
            }
        }
        return "";
    }

    private List<String> getContainFieldStr() {
        List<String> res = new ArrayList<>(rows.length);
        for (String s : rows) {
            s = s.trim();
            if (isContainField(s)) {
                s = s.replace("\n", "").replace("\t", "");
                res.add(s);
            }
        }
        return res;
    }

    private boolean isContainField(String str) {
        String[] split = str.split(" ");
        if (split.length < 2) {
            return false;
        }
        String fieldType = split[1];
        int indexOf = split[1].indexOf("(");
        if (indexOf != -1) {
            fieldType = split[1].substring(0, indexOf);
        }
        Boolean isContainsField = MYSQL_FIELD_TYPE_MAP.get(fieldType.toUpperCase());
        return isContainsField != null;
    }

    private List<Field> getFields(List<String> strContainsFieldList) {
        return strContainsFieldList.stream().map(strContainsField -> {
            String[] fieldInfo = strContainsField.split(" ");
            String fieldName = fieldInfo[0].replace("`", "");
            String fieldType = fieldInfo[1];
            String lastEl = fieldInfo[fieldInfo.length - 1];
            String fieldComment = null;
            if (lastEl.contains("'")) {
                fieldComment = lastEl.replace("'", "").replace(",", "");
            }
            return new Field(fieldName, fieldType,fieldComment);

        }).collect(Collectors.toList());
    }
}
